/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.webos.java.jabber;

import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.proxy.ProxyInfo;
import org.json.JSONObject;
import org.webos.java.base.Frame;
import org.webos.java.base.FrameType;
import org.webos.java.base.NetworkManager;
import org.webos.java.base.RemoteMessage;
import org.webos.java.base.SessionStateListener;
import org.webos.java.base.tree.TreeController;
import org.webos.java.base.tree.TreeControllerItem;
import org.webos.java.base.workspace.Workspace;
import org.webos.java.jabber.chat.ChatFrame;
import org.webos.java.jabber.chat.GroupMessage;
import org.webos.java.jabber.tree.ConnectionItem;
import org.webos.java.jabber.tree.GroupItem;
import org.webos.java.jabber.tree.UserItem;
import org.webos.java.root.Log;

/**
 *
 * @author Kostya
 */

@FrameType(code="jabber-roster", jsClass="jabber.Roster")
public class RosterFrame extends Frame implements ConnectionListener, ConnectionCreationListener, SessionStateListener{

    private TreeController<ConnectionItem> treeController = null;
    private String settingName = null;
    private JabberApp jabberApp = null;

    public RosterFrame(JabberApp app, Workspace aWorkspace, String aSettingName) {
        super(app, aWorkspace);
        jabberApp = app;
        jabberApp.getSession().addSessionStateListener(this);
        this.settingName = aSettingName;
        treeController = new TreeController<ConnectionItem>(this);
        XMPPConnection.addConnectionCreationListener(this);
        addConnection(aSettingName);
        setIcon("jabber_t_icn jabber_t_main");
    }

    public void addConnection(String aSettingName){
        //At this stage, simply stop all connections and create new
        for (int i = 0; i < treeController.getChildrenCount(); i++) {
            ConnectionItem ci = treeController.getChild(i);
            ci.setStatus(ConnectionItem.STATUS_OFFLINE);
        }
        treeController.getRoot().clear();
        try {
            ConnectionItem itm = new ConnectionItem(jabberApp, treeController, aSettingName);
            treeController.getRoot().insertChild(treeController.getChildrenCount(), itm);
            itm.setStatus(ConnectionItem.STATUS_ONLINE);
        } catch (Throwable t) {
            Log.error(this, "Exception thrown: " + t.getMessage());
            t.printStackTrace();
        }
    }

    public ConnectionItem getConnectionItem(String aFrom){
        for (int i = 0; i < treeController.getChildrenCount(); i++) {
            ConnectionItem itm = treeController.getChild(i);
            if(itm.getUserName().equalsIgnoreCase(aFrom)){
                return itm;
            }
        }
        return null;
    }

    public boolean sendMessage(String aFrom, String aTo, String aMessage){
        try {
            ConnectionItem itm = getConnectionItem(aFrom);
            if(itm!=null){
                Chat chat = itm.getChat(aTo);
                chat.sendMessage(aMessage);
                return true;
            }
        } catch (Throwable t) {
            Log.error(this, "Exception thrown: " + t.getMessage());
            t.printStackTrace();
        }
        return false;
    }

    @RemoteMessage
    public JSONObject moveEntry(JSONObject aONObject){
        try {
            UserItem item = (UserItem) treeController.findItemByID(aONObject.optString("user"), treeController.getRoot());
            GroupItem groupItem = (GroupItem) treeController.
                    findItemByID(aONObject.optString("group"), treeController.getRoot());
            if(item!=null && groupItem!=null){
                ConnectionItem conn = (ConnectionItem) groupItem.getParent();
                conn.moveEntry(item, groupItem);
            }
            return null;
        } catch (Throwable t) {
            Log.error(this, "Exception thrown: " + t.getMessage());
            t.printStackTrace();
        }
        return NetworkManager.getErrorObject(920, "Can't move entry");
    }

    @RemoteMessage
    public JSONObject startAddEntry(JSONObject aObject){
        try {
            TreeControllerItem item = treeController.getSelected();
            if(item==null && treeController.getChildrenCount()==0)
                return null;
            if(item==null)
                item = treeController.getChild(0);
            GroupItem gi = null;
            ConnectionItem ci = null;
            if(item instanceof ConnectionItem){
                ci = (ConnectionItem) item;
                gi = ci.getGeneralGroup();
            }
            if(item instanceof UserItem){
                gi = (GroupItem) item.getParent();
                ci = (ConnectionItem) gi.getParent();
            }
            if(item instanceof GroupItem){
                gi = (GroupItem) item;
                ci = (ConnectionItem) gi.getParent();
            }
            new AddEntryDialog(jabberApp, gi, ci);
        } catch (Throwable t) {
            Log.error(this, "Exception thrown: " + t.getMessage());
            t.printStackTrace();
            return NetworkManager.getErrorObject(814, "Can't add entry");
        }
        return null;
    }

    @RemoteMessage
    public JSONObject removeEntry(JSONObject aObject){
        try {
            TreeControllerItem item = treeController.getSelected();
            if(item==null || !(item instanceof UserItem))
                return NetworkManager.getErrorObject(811, "Command is applied only to contact entries");
            UserItem ui = (UserItem) item;
            ConnectionItem ci = (ConnectionItem) ui.getParent().getParent();
            ci.getRoster().removeEntry(ui.getObject());
            ui.remove();
        } catch (Throwable t) {
            Log.error(this, "Exception thrown: " + t.getMessage());
            t.printStackTrace();
            return NetworkManager.getErrorObject(812, "Can't remove contact");
        }
        return null;
    }

    @RemoteMessage
    public void openSelectedChat(JSONObject aObject){
        try {
            TreeControllerItem itm = treeController.getSelected();
            if(itm==null)
                return;
            if(itm instanceof GroupItem){
                if(itm.getChildrenCount()>0)
                    new GroupMessage(jabberApp,(GroupItem) itm);
                return;
            }
            if(itm instanceof ConnectionItem)
                return;
            UserItem item = (UserItem) treeController.getSelected();
            ConnectionItem conn = (ConnectionItem) item.getParent().getParent();//Group, Connection
            String idToSearch = item.getUserJID()+conn.getUserName();
            ChatFrame chatFrame = jabberApp.getChatFrame(idToSearch, conn, item.getUserName(), item.getUserJID());
            if(chatFrame!=null){
                int entryStatus = item.getCurrentStatus();
                chatFrame.setIcon("jabber_icn jabber_"+entryStatus);
                jabberApp.showFrame(chatFrame);
            }
        } catch (Throwable t) {
            Log.error(this, "Exception thrown: " + t.getMessage());
            t.printStackTrace();
        }
    }

    @RemoteMessage
    public void openChat(JSONObject aObject){
        try {
            UserItem item = (UserItem) treeController.findItemByID(aObject.optString("id", ""), treeController.getRoot());
            if(item==null)
                return;
            ConnectionItem conn = (ConnectionItem) item.getParent().getParent();//Group, Connection
            String idToSearch = item.getUserJID()+conn.getUserName();
            ChatFrame chatFrame = jabberApp.getChatFrame(idToSearch, conn, item.getUserName(), item.getUserJID());
            if(chatFrame!=null){
                int entryStatus = item.getCurrentStatus();
                chatFrame.setIcon("jabber_icn jabber_"+entryStatus);
                jabberApp.showFrame(chatFrame);
            }
        } catch (Throwable t) {
            Log.error(this, "Exception thrown: " + t.getMessage());
            t.printStackTrace();
        }
    }

    @RemoteMessage
    public JSONObject setStatus(JSONObject aData){
        try {
            JSONObject result = null;
            int newStatus = aData.optInt("status", 1);
            for (int i = 0; i < treeController.getChildrenCount(); i++) {
                ConnectionItem itm = treeController.getChild(i);
                if(!itm.setStatus(newStatus))
                    result = NetworkManager.getErrorObject(802, "Can't set new status");
            }
            return result;
        } catch (Throwable t) {
            Log.error(this, "Exception thrown: " + t.getMessage());
            t.printStackTrace();
        }
        return null;
    }

    @RemoteMessage
    public JSONObject getTree(JSONObject aData){
        return treeController.getTree();
    }
    
    @RemoteMessage
    public JSONObject selectionChanged(JSONObject aData){
        try {
            treeController.selectionChanged(aData.getString("id"));
        } catch (Throwable t) {
            Log.error(this, "Exception thrown: " + t.getMessage());
            t.printStackTrace();
        }
        return null;
    }
    
    @RemoteMessage
    public void setState(JSONObject aData){
        try {
            treeController.setState(aData.getString("id"), aData.getBoolean("collapsed"));
        } catch (Throwable t) {
            Log.error(this, "Exception thrown: " + t.getMessage());
            t.printStackTrace();
        }
    }

    @RemoteMessage
    public void openSettingsDialog(JSONObject aData){
        new SettingsDialog((JabberApp) getApplication(), settingName);
    }

    public void connectionClosed() {
        Log.debug(this, "Connection closed");
    }

    public void connectionClosedOnError(Exception arg0) {
        Log.debug(this, "Connection Closed On Error");
    }

    public void reconnectingIn(int arg0) {
        Log.debug(this, "Reconnecting in... "+arg0);
    }

    public void reconnectionSuccessful() {
        Log.debug(this, "Reconnect OK");
    }

    public void reconnectionFailed(Exception arg0) {
        Log.debug(this, "Reconnection failed");
    }

    public void connectionCreated(XMPPConnection arg0) {
        Log.debug(this, "Connection created... "+arg0.getConnectionID());
    }

    @Override
    protected void finalize() throws Throwable {
        terminate();
    }

    @Override
    public void terminate() {
        for (int i = 0; i < treeController.getChildrenCount(); i++) {
            ConnectionItem ci = treeController.getChild(i);
            ci.setStatus(ConnectionItem.STATUS_OFFLINE);
        }
        jabberApp.getSession().removeSessionStateListener(this);
    }

    public void sessionOnline() {
        for (int i = 0; i < treeController.getChildrenCount(); i++) {
            ConnectionItem ci = treeController.getChild(i);
            ci.sessionOnline();

        }
    }

    public void sessionOffline() {
        jabberApp.setActiveChat(null);
        for (int i = 0; i < treeController.getChildrenCount(); i++) {
            ConnectionItem ci = treeController.getChild(i);
            ci.sessionOffline();

        }
    }
}
